package feizhou.untils.tools.io;

import feizhou.untils.tools.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Slf4j
public class FileUtil {

    private static List<String> suffixs = new ArrayList<>();

    static {
        suffixs.add(".txt");
        suffixs.add(".pdf");
        suffixs.add(".doc");
        suffixs.add(".docx");
        suffixs.add(".jpg");
        suffixs.add(".gif");
        suffixs.add(".png");
        suffixs.add(".mp4");
        suffixs.add(".mov");
        suffixs.add(".mp3");
        suffixs.add(".rar");
        suffixs.add(".zip");
        suffixs.add(".exe");
        suffixs.add(".bak");
        suffixs.add(".ppt");
        suffixs.add(".htm");
        suffixs.add(".html");
        suffixs.add(".yml");
        suffixs.add(".xml");
        suffixs.add(".properties");
    }

    /**
     * 图片压缩
     *
     * @param inputStream 源图片的输入流
     * @param destUrl     压缩后的图片的地址
     */
    public static void compressFile(InputStream inputStream, String destUrl) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        if (new File(destUrl).exists()) {
            return;
        }
        log.info("图片缩放开始========");
        try {
            // 1、定义图像文件对象
            // 2、定义图像图像数据的访问的缓冲器
            BufferedImage bufferedImage = ImageIO.read(inputStream);
            // 3、获取图片的原始宽高
            int width = bufferedImage.getWidth();
            int height = bufferedImage.getHeight();
            // 4、获取图片的缩放【宽高都是*了缩放比例的再取整】
            Image scaledInstance = bufferedImage.getScaledInstance(Double.valueOf(width * 0.1).intValue(), Double.valueOf(height * 0.1).intValue(), Image.SCALE_DEFAULT);
            // 5、将Image类型转换成BufferedImage对象[BufferedImage.TYPE_INT_ARGB：表示具有8位RGBA颜色成分的整数像素的图像]
            BufferedImage newImage = new BufferedImage(Double.valueOf(width * 0.1).intValue(), Double.valueOf(height * 0.1).intValue(), BufferedImage.TYPE_INT_BGR);
            // 一个新的图形上下文，这是这个图形上下文的副本
            Graphics g = newImage.getGraphics();
            // 绘制图片大小
            g.drawImage(scaledInstance, 0, 0, null);
            // 释放文件资源
            g.dispose();
            // 将新的图片文件写入到指定的文件夹中
            String formatName = destUrl.substring(destUrl.lastIndexOf(".") + 1);
            ImageIO.write(newImage, formatName, new File(destUrl));
        } catch (Exception e) {
            log.error("图片缩放出错，错误信息{}", e.getMessage());
        }
        stopWatch.stop();
        log.info("图片缩放成功 总耗时:{}", stopWatch.getTotalTimeMillis());
    }

    /**
     * 多个文件打zip包
     *
     * @param list    zip包里面的文件信息集合
     * @param zipFile 压缩后的zip包文件
     */
    public static void zipFiles(List<File> list, File zipFile) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        FileOutputStream fileOutputStream = null;
        ZipOutputStream zipOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(zipFile);
            zipOutputStream = new ZipOutputStream(fileOutputStream);
            // 创建 ZipEntry 对象
            ZipEntry zipEntry;
            // 遍历源文件数组
            for (File file : list) {
                // 将源文件数组中的当前文件读入 FileInputStream 流中
                // 实例化 ZipEntry 对象，源文件数组中的当前文件
                zipEntry = new ZipEntry(file.getName());
                zipOutputStream.putNextEntry(zipEntry);
                // 该变量记录每次真正读的字节个数
                int len;
                // 定义每次读取的字节数组
                byte[] buffer = new byte[1024];
                while (!((len = new FileInputStream(file).read(buffer)) <= 0)) {
                    zipOutputStream.write(buffer, 0, len);
                }
            }

        } catch (Exception e) {
            log.error("压缩图片出错，错误信息{}", e.getMessage());
        } finally {
            try {
                if (zipOutputStream != null) {
                    zipOutputStream.closeEntry();
                    zipOutputStream.close();
                }
            } catch (IOException e) {
                log.error("压缩图片出错，错误信息{}", e.getMessage());
            }
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                log.error("压缩图片出错，错误信息{}", e.getMessage());
            }
        }
        stopWatch.stop();
        log.info("图片压缩zip包耗时：{}", stopWatch.getTotalTimeMillis());
    }

    /**
     * 下载文件
     *
     * @param sourceUrl 源文件的http格式的url路径
     * @param descUrl   下载后的目标文件的地址
     */
    public static void downloadUrlFile(String sourceUrl, String descUrl) {
        if (new File(descUrl).exists()) {
            return;
        }
        InputStream is = null;
        FileOutputStream os = null;
        try {
            // 构造URL
            URL url = new URL(sourceUrl);
            // 打开连接
            URLConnection con = url.openConnection();
            // 输入流
            is = con.getInputStream();
            // 1K的数据缓冲
            byte[] bs = new byte[1024];
            // 读取到的数据长度
            int len;
            // 输出的文件流
            File file = new File(descUrl);
            os = new FileOutputStream(file, true);
            // 开始读取
            while ((len = is.read(bs)) != -1) {
                os.write(bs, 0, len);
            }
        } catch (Exception e) {
            log.error("downloadUrlFile error sourceUrl={},descUrl={}", sourceUrl, descUrl, e);
        } finally {
            // 完毕，关闭所有链接
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
    }

    /**
     * 获取所有文件
     *
     * @param path    文件路径
     * @param suffixs 包含的后缀名
     * @return java.util.List<java.io.File>
     * @author <a href="920786312@qq.com">周飞</a>
     * @since 2023/10/8 10:42
     */
    public static List<File> getALlFile(String path, List<String> suffixs) {
        List<File> files = new ArrayList<>();
        getFile(new File(path), files, suffixs);
        return files;
    }

    /**
     * 获取所有文件
     *
     * @return java.util.List<File>
     * @path 文件路径
     * @author <a href="920786312@qq.com">周飞</a>
     * @since 2023/9/28 16:28
     */
    public static List<File> getALlFile(String path) {
        List<File> files = new ArrayList<>();
        getFile(new File(path), files);
        return files;
    }

    private static void getFile(File file, List<File> files, List<String> suffixs) {
        //如果是文件，就不递归了
        if (file.isFile()) {
            return;
        }
        //递归所有文件
        File[] tempFiles = file.listFiles();
        //处理文件情况
        Arrays.stream(tempFiles).filter(e -> e.isFile()).filter(e -> suffixs.contains(getSuffix(e.getName()))).forEach(e -> {
            files.add(e);
        });
        //处理非文件情况，需要递归
        Arrays.stream(tempFiles).filter(e -> !e.isFile()).forEach(e -> {
            getFile(e, files, suffixs);
        });
    }

    private static void getFile(File file, List<File> files) {
        //如果是文件，就不递归了
        if (file.isFile()) {
            return;
        }
        //递归所有文件
        File[] tempFiles = file.listFiles();
        //处理文件情况
        Arrays.stream(tempFiles).filter(e -> e.isFile()).forEach(e -> {
            files.add(e);
        });
        //处理非文件情况，需要递归
        Arrays.stream(tempFiles).filter(e -> !e.isFile()).forEach(e -> {
            getFile(e, files);
        });
    }


    /**
     * 删除文件
     */
    public static void deleteFile(String... urls) {
        for (String url : urls) {
            try {
                if (StringUtil.isNotEmpty(url)) {
                    Files.deleteIfExists(Paths.get(url));
                }
            } catch (IOException e) {
                log.error("deleteFile error url={} error ", url, e);
            }
        }
    }

    /**
     * 删除目录
     *
     * @param folder
     */
    public static void deleteDir(File folder) {
        File[] files = folder.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDir(file);
                } else {
                    file.delete();
                }
            }
        }
        folder.delete();
    }

    /**
     * 删除目录
     *
     * @param dirPath
     */
    public static void deleteDir(String dirPath) {
        deleteDir(new File(dirPath));
    }


    /**
     * 获取文件名后缀
     *
     * @param fileAddr
     * @return java.lang.String
     * @author <a href="920786312@qq.com">周飞</a>
     * @since 2023/10/7 16:35
     */
    public static String getSuffix(String fileAddr) {
        int index = fileAddr.lastIndexOf(".");
        if (index == -1) {
            return null;
        }
        String suffix = fileAddr.substring(index);
        //去除其他字段
        if (suffix.contains("#")) {
            suffix = suffix.substring(0, suffix.lastIndexOf("#"));
        }
        if (suffix.contains("?")) {
            suffix = suffix.substring(0, suffix.lastIndexOf("?"));
        }

        // 文件名后缀长度太大情况
        if (suffix.length() > 20) {
            log.error("文件名后缀长度太大：" + fileAddr);
            for (String suf : suffixs) {
                if (suffix.contains(suf)) {
                    return suf;
                }
            }
            return null;
        }

        return suffix;
    }


    /**
     * 创建目录
     *
     * @param dirPath
     * @return void
     * @author <a href="920786312@qq.com">周飞</a>
     * @since 2023/11/28 16:31
     */
    public static void mkdirs(String dirPath) {
        File file = new File(dirPath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    public static void main(String[] args) {
        List<File> aLlFile = getALlFile("H:\\temp\\actuator 学习");
        aLlFile.forEach(System.out::println);

    }
}
